package cn.edu.nju.software.greencreditsystem.business;

import cn.edu.nju.software.greencreditsystem.DAO.FinancialFactorDAO;
import cn.edu.nju.software.greencreditsystem.DAO.LogisticHistoryDAO;
import cn.edu.nju.software.greencreditsystem.DAO.SystemConstantDAO;
import cn.edu.nju.software.greencreditsystem.DAOImpl.FinancialFactorDAOImpl;
import cn.edu.nju.software.greencreditsystem.domain.LogisticHistory;
import cn.edu.nju.software.greencreditsystem.domain.LogisticEnterprise;
import cn.edu.nju.software.greencreditsystem.factory.DAOFactory;
import cn.edu.nju.software.greencreditsystem.factory.SessionPool;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import org.hibernate.Session;
import org.math.R.Rsession;
import org.rosuda.REngine.REXP;
import org.rosuda.REngine.REXPMismatchException;

/**
 * 作者：何启睿
 * 创建时间：2011-8-2
 * 类描述：财务预警工具类（实现）
 */
public class LogisticPredictor implements FinancialPredictor
{
    private Rsession r;
    private boolean isUsable[];
    

    @Override
    public boolean init(double p) 
    {
        r = Rsession.newInstanceTry(System.out, null);
        LogisticHistoryDAO logDao = DAOFactory.getLogisticHistoryDAOInstance();
        SystemConstantDAO scdao = DAOFactory.getSystemConstantDAOInstance();
        double xGood[][] = logDao.getOrderlyGood();
        double xBad[][] = logDao.getOrderlyBad();
        
        double y[] = new double[xGood.length + xBad.length];
        if(y.length < scdao.get("leastLogisticHistory"))
            return false;
        
        for(int i = 0; i < xGood.length; i++)
            y[i] = 0;
        for(int i = 0; i < xBad.length; i++)
            y[i  + xGood.length] = 1;
        
        filter(xGood, xBad, y, p);
        
        //Xi <- c(....)
        String commandX;
        for(int j = 0; j < xGood[0].length; j++)
        {
            if(isUsable[j])
            {
                commandX = "X" + j + " <- c(";
                for(int i = 0; i < y.length; i++)
                {
                    if(i < xGood.length)
                        commandX += xGood[i][j];
                    else
                        commandX += xBad[i - xGood.length][j];
                    
                    if(i < y.length - 1)
                        commandX += ", ";
                }
                commandX += ")";
                r.eval(commandX);
            }
        }
        
        //Y <- c(....)
        String commandY = "Y <- c(";
        for(int i = 0; i < y.length; i++)
        {
            commandY += y[i];
            if(i < y.length -1)
                commandY += ", ";
        }
        commandY += ")";
        r.eval(commandY); 
        
        //d <- data.frame(X0, X1...., Y)
        String commandD = "d <- data.frame(";
        for(int j = 0; j < isUsable.length; j++)
        {
            if(isUsable[j])
                commandD = commandD + "X" + j + ", ";
        }
        commandD += "Y)";
        r.eval(commandD); 
        
        //logistic <- glm(Y ~ X0+X1...., family=binomial, data=d)
        String commandL = "logistic <- glm(Y~";
        for(int j = 0; j < isUsable.length; j++)
        {
            if(isUsable[j])
            {
                commandL = commandL + "X" + j;
                if(j < isUsable.length - 1)
                    commandL += "+";
            }
        }
        if(commandL.endsWith("+"))
            commandL = commandL.substring(0, commandL.length() - 1);
        
        commandL += ", family=binomial(logit), data = d)";
        r.eval(commandL);
        
        return true;
    }

    @Override
    public boolean refreshHistory(String xmlPath, String excelRarPath) 
    {
        boolean result = false;
        
        Session s = SessionPool.getSession();
        s.beginTransaction();
        try
        {
            String dirName = "tempdir" + System.currentTimeMillis() + "/";
            File dir = new File(dirName);
            dir.mkdir();
            String winrarCmd = "C:\\Program Files\\WinRAR\\WinRAR.exe  x -r -p- -o+ " + excelRarPath + " " + dirName;
            Runtime rt = Runtime.getRuntime();
            Process pro = rt.exec(winrarCmd);
            pro.waitFor();
            
            String excelPaths[] = dir.list();
            for(int i = 0; i < excelPaths.length; i++)
                excelPaths[i] = dirName + excelPaths[i];
            
            s.createQuery("delete from LogisticHistory").executeUpdate();
            s.createQuery("delete from LogisticEnterprise").executeUpdate();
            
            WoleAnalyser analyser = new WoleAnalyser();
            FinancialFactorDAO ffdao = new FinancialFactorDAOImpl();
            double temp[];
            for(String excelPath:excelPaths)
            {
                temp = analyser.getIndex(xmlPath, excelPath);
                LogisticEnterprise le = new LogisticEnterprise();
                if(excelPath.endsWith("good.xls") || excelPath.endsWith("good.xlsx"))
                    le.setIsGood(true);
                else
                    le.setIsGood(false);
                
                s.save(le);
                for(int i = 0; i < temp.length; i++)
                {
                    LogisticHistory lh = new LogisticHistory();
                    lh.setEnterprise(le);
                    lh.setFinancialFactor(ffdao.getByName(WoleAnalyser.factorNames[i]));
                    lh.setValue(temp[i]);
                    s.save(lh);
                }
            }
            
            File files[] = dir.listFiles();
            for(int i = 0; i < files.length; i++)
                files[i].delete();
            dir.delete();
            s.getTransaction().commit();
            result = true;
        }catch(Exception ex)
        {
            ex.printStackTrace();
            s.getTransaction().rollback();
        }
        finally
        {
            s.close();
        }
        
        return result;
    }

    @Override
    public double estimate(double[] index) 
    {
        //Xi <- c(.)
        //nd <- data.frame(X0 = X0, X1 = X1....)
        String commandX;
        String commandN = "nd <- data.frame(";
        for(int i = 0; i < index.length; i++)
        {
            if(isUsable[i])
            {
                commandX = "X" + i + " <- c(" + index[i] + ")";
                r.eval(commandX);
                
                commandN = commandN + "X" + i + " = X" + i;
                if(i < index.length - 1)
                    commandN += ", ";
            }
        }
        if(commandN.endsWith(", "))
            commandN = commandN.substring(0, commandN.length() - 2);
        commandN += ")";
        r.eval(commandN);
        
        //p <- predict(logistic, nd, type='response')
        String commandP = "p <- predict(logistic, nd, type='response')";
        REXP temp = r.eval(commandP);
        double result = -1;
        try
        {
            result = temp.asDouble();
        } catch (REXPMismatchException ex)
        {
            ex.printStackTrace();
        }
        
        return result;
    }
    
    /**
     * 方法描述：清空此对象成员数据，停止R服务，执行后此对象必须再次初始化才能使用
     * param：
     * return：
    */ 
    @Override
    public void end()
    {
        isUsable = null;
        r.end();
    }

    /**
     * 方法描述：私有辅助方法，从X中剔除相关系数很小于p者
     * param：2个x二维数组和y数组和最小相关系数p
     * return：
    */ 
    private void filter(double xGood[][], double xBad[][], double y[], double p)
    {
        //Xi <- c(....)
        String commandX;
        for(int j = 0; j < xGood[0].length; j++)
        {
            commandX = "X" + j + " <- c(";
            for(int i = 0; i < y.length; i++)
            {
                if(i < xGood.length)
                    commandX += xGood[i][j];
                else
                    commandX += xBad[i - xGood.length][j];
                
                if(i < y.length - 1)
                    commandX += ", ";
            }
            commandX += ")";
            r.eval(commandX);
        }
        
        //Y <- c(....)
        String commandY = "Y <- c(";
        for(int i = 0; i < y.length; i++)
        {
            commandY += y[i];
            if(i < y.length -1)
                commandY += ", ";
        }
        commandY += ")";
        r.eval(commandY); 
        
        isUsable = new boolean[xGood[0].length];
        for(int i = 0; i < isUsable.length; i++)
        {
            try
            {
                //cor(Xi, Y)
                REXP rexp = r.eval("cor(X" + i + ", Y)");
                if(Math.abs(rexp.asDouble()) < p)
                    isUsable[i] = false;
                else
                    isUsable[i] = true;
            }catch (REXPMismatchException ex)
            {
                ex.printStackTrace();
            }
        }
    }
    
}
